import ij.IJ;
import ij.ImagePlus;
import ij.WindowManager;
import ij.gui.GUI;
import ij.gui.Plot;
import ij.gui.Roi;
import ij.measure.Measurements;

import ij.plugin.frame.*;

import ij.process.ImageProcessor;
import ij.process.ImageStatistics;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;


public class Intensity_ extends PlugInFrame implements ActionListener {
	public static final String GET_MAX_COMMAND = "GetMax";
	public static final String GET_MIN_COMMAND = "GetMin";
	public static final String GET_MIN_MAX_COMMAND = "Find min and max";
	public static final String CALCULATE_COMMAND = "Calculate";
	public static final String SPECTRUM_COMMAND = "DrawSpectrum";
	public static final String RADIAL_SPECTRUM_COMMAND = "RadialSpectrum";
	public static final String MIN_INPUT = "Minimum";
	public static final String MAX_INPUT = "Maximum";
	public static final String DISTANCE_INPUT = "Distance";
	public static final String MEAN_RESULT = "Mean";
	public static final String DEVIATION_RESULT = "Standard Deviation";
	public static final String KURTOSIS_RESULT = "Kurtosis";
	public static final String SKEWNESS_RESULT = "Skewness";
	public static final String ECHOGENICITY_RESULT = "Echogenicity";


	public double min = 0;
	public double max = 255;

	private double mean = Double.NaN;
	private double deviation = Double.NaN;
	private double kurtosis = Double.NaN;
	private double skewness = Double.NaN;
	private double echogenicity = Double.NaN;
	private double corr = Double.NaN;
	private double spec = Double.NaN;

	private ImagePlus imp;
	private ImageProcessor ip;
	private Panel mainPane;

	private Map<String, TextField> commandFields = new TreeMap<String, TextField>();
	private Map<String, Label> results = new TreeMap<String, Label>();
	private Map<String, TextField> inputs = new TreeMap<String, TextField>();

	public Intensity_() {
		super("Intensity Analysis");
		imp = WindowManager.getCurrentImage();
		if (imp == null) {
			IJ.showMessage("No image", "There are no images open.");
			return;
		}

		mainPane = new Panel();

		mainPane.setLayout(new GridLayout(0, 3, 10, 5));
		addNonEditableInput(MIN_INPUT, min);
		addNonEditableInput(MAX_INPUT, max);
		addCommand(GET_MIN_MAX_COMMAND);
		addResult(ECHOGENICITY_RESULT);
		addResult(MEAN_RESULT);
		addResult(DEVIATION_RESULT);
		addResult(SKEWNESS_RESULT);
		addResult(KURTOSIS_RESULT);
		addCommand(CALCULATE_COMMAND);
		add(mainPane);

		pack();
		setVisible(true);
		GUI.center(this);
	}

	public void run(java.lang.String arg) {
		if (imp == null) {
			return;
		}
		ip = imp.getProcessor();
		Roi roi = imp.getRoi();
	}

	private void addCommand(String labelText, String buttonText,
			double defaultValue) {
		Label label = new Label(labelText);
		TextField textField = new TextField(String.format("%.0f", defaultValue));
		commandFields.put(buttonText, textField);
		inputs.put(labelText, textField);
		Button button = new Button(buttonText);
		button.addActionListener(this);
		button.setActionCommand(buttonText);
		mainPane.add(label);
		mainPane.add(textField);
		mainPane.add(button);
	}

	private void addNonEditableInput(String labelText, double defaultValue) {
		Label label = new Label(labelText);
		TextField textField = new TextField(String.format("%.0f", defaultValue));
		textField.setEditable(false);
		inputs.put(labelText, textField);
		mainPane.add(label);
		mainPane.add(textField);
		addLabel("");
	}

	private void addResult(String resultName) {
		Label nameLabel = new Label(resultName);
		Label resultLabel = new Label();
		results.put(resultName, resultLabel);
		mainPane.add(nameLabel);
		mainPane.add(resultLabel);
		addLabel("");
	}

	private void addCommand(String buttonText) {
		Button button = new Button(buttonText);
		button.addActionListener(this);
		button.setActionCommand(buttonText);
		addLabel("");
		mainPane.add(button);
		addLabel("");
	}

	private void addLabel(String labelText) {
		mainPane.add(new Label(labelText));
	}

	private void addDoubleField(double val) {
		TextField field = new TextField(String.format("%.0f", val));
		field.setEditable(false);
		mainPane.add(field);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		imp = WindowManager.getCurrentImage();
		String command = e.getActionCommand();
		if (GET_MAX_COMMAND.equals(command)) {
			max = getMax();
			commandFields.get(GET_MAX_COMMAND).setText(precisionFormat(max, 0));
		} else if (GET_MIN_COMMAND.equals(command)) {
			min = getMin();
			commandFields.get(GET_MIN_COMMAND).setText(precisionFormat(min, 0));
		} else if (GET_MIN_MAX_COMMAND.equals(command)) {
			setMinMax();
			inputs.get(MIN_INPUT).setText(precisionFormat(min, 0));
			inputs.get(MAX_INPUT).setText(precisionFormat(max, 0));
		} else if (CALCULATE_COMMAND.equals(command)) {
			calculate();
			results.get(MEAN_RESULT).setText(format(mean));
			results.get(DEVIATION_RESULT).setText(format(deviation));
			results.get(SKEWNESS_RESULT).setText(format(skewness));
			results.get(KURTOSIS_RESULT).setText(format(kurtosis));
			results.get(ECHOGENICITY_RESULT).setText(
					precisionFormat(echogenicity, 2) + "%");
		} 
	}

	
	private void setMinMax() {
		ip.snapshot();
		ip.smooth();
		min = getMin();
		max = getMax();
		ip.reset();
	}

	private double getMax() {
		return imp.getStatistics().max;
	}

	private double getMin() {
		return imp.getStatistics().min;
	}

	private void calculate() {
		imp = WindowManager.getCurrentImage();
		if (imp == null) {
			IJ.showMessage("No image", "There are no images open.");
			return;
		}
		max = Double.parseDouble(inputs.get(MAX_INPUT).getText());
		min = Double.parseDouble(inputs.get(MIN_INPUT).getText());
		ip.snapshot();
		ip.smooth();
		double realMax = getMax();
		double realMin = getMin();
		double fakeMin = (max * realMin - min * realMax) / (max - min);
		double fakeMax = fakeMin + 255.0 * (realMax - realMin) / (max - min);
		ip.setMinAndMax(fakeMin, fakeMax);

		ImageStatistics stat = imp.getStatistics(Measurements.MIN_MAX
				+ Measurements.STD_DEV + Measurements.KURTOSIS
				+ Measurements.SKEWNESS);
		mean = stat.mean;
		deviation = stat.stdDev;
		skewness = stat.skewness;
		kurtosis = stat.kurtosis;
		echogenicity = 100.0 * (mean - min) / (max - min);
		ip.reset();
		PlainHistogramWindow h = new PlainHistogramWindow("Histogram of "
				+ imp.getShortTitle(), this.imp, 20);
	}

	
	private String format(double d) {
		return String.format("%f", d);
	}

	private String precisionFormat(double d, int precision) {
		return String.format("%." + precision + "f", d);
	}

}
